package com.atguigu.yygh.user.api;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.net.URLEncoder;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.yygh.common.result.R;
import com.atguigu.yygh.user.service.UserInfoService;
import com.atguigu.yygh.user.utils.ConstantPropertiesUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 孔德成
 * @slogan 致敬大师，致敬未来的你
 * @date 2021/9/8 10:43 下午
 * @desc 参考：https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
 * 微信扫码登陆流程：
 * 1. 请求 code
 * 2. 通过 code 获取 access_token
 * 3. 通过 access_token 调用接口
 * JS微信登录流程
 * 1. 用户请求 /api/user/wx/getLoginParam 接口获取生成二维码的必要参数
 * 2. 前端引入 http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
 * 3. 在需要使用微信登录的地方实例以下JS对象:
 * var obj = new WxLogin({
 * self_redirect:true,
 * id:"login_container",
 * appid: "",
 * scope: "",
 * redirect_uri: "",
 * state: "",
 * style: "",
 * href: ""
 * });
 * 4. 用户扫码确认登陆
 * 5. 微信平台回调 redirect_uri 接口，返回 code 和 state 参数
 * 6. 使用 code 请求
 * https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
 * 获取 access_token
 * 7. 通过 access_token 调用 /sns/userinfo 获取用户信息
 * 8. 执行平台登陆业务
 * 授权后接口调用参考：https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Authorized_Interface_Calling_UnionID.html
 */
@Controller
@RequestMapping("/api/user/wx")
@Slf4j
public class WeixinApiController {

    private final UserInfoService userInfoService;

    public WeixinApiController(UserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }

    /**
     * 获取生成微信二维码参数
     */
    @GetMapping("getLoginParam")
    @ResponseBody
    public R genQrConnect() {
        // url 强制编码
        String redirectUri = URLEncoder.ALL.encode(ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL, CharsetUtil.CHARSET_UTF_8);
        log.info("redirectUri: " + redirectUri);
        Map<String, Object> map = new HashMap<>(4);
        map.put("appid", ConstantPropertiesUtil.WX_OPEN_APP_ID);
        map.put("redirectUri", redirectUri);
        map.put("scope", "snsapi_login");
        map.put("state", System.currentTimeMillis() + "");
        return R.ok().data(map);
    }

    /**
     * 微信扫码用户授权登陆后回调接口
     */
    @GetMapping("callback")
    public String callback(String code, String state) {
        log.info("code: " + code);
        log.info("state: " + state);
        // 通过 code 获取 access_token
        HashMap<String, Object> paramMap = new HashMap<>(4);
        paramMap.put("appid", ConstantPropertiesUtil.WX_OPEN_APP_ID);
        paramMap.put("secret", ConstantPropertiesUtil.WX_OPEN_APP_SECRET);
        paramMap.put("code", code);
        paramMap.put("grant_type", "authorization_code");
        String wxBaseUrl = "https://api.weixin.qq.com";
        String resContent = HttpUtil.get(wxBaseUrl + "/sns/oauth2/access_token", paramMap);
        log.info(resContent);
        // 将响应内容转为 JSONObject
        JSONObject resJson = JSONObject.parseObject(resContent);
        paramMap.clear();
        // 通过 access_token 和 openid 调用获取用户信息接口
        paramMap.put("access_token", resJson.getString("access_token"));
        paramMap.put("openid", resJson.getString("openid"));
        String userInfoStr = HttpUtil.get(wxBaseUrl + "/sns/userinfo", paramMap);
        log.info(userInfoStr);
        // 用户信息
        JSONObject userInfoJson = JSONObject.parseObject(userInfoStr);
        // 用户登陆
        Map<String, Object> map = userInfoService.wxLogin(userInfoJson);

        // 重定向到前端，将 token，openid 和 name 传递到前端
        String redirectUrl = "http://localhost:3000/weixin/callback?token=%s&openid=%s&name=%s";
        String token = MapUtil.getStr(map, "token", "");
        String openid = MapUtil.getStr(map, "openid", "");
        String name = URLEncoder.ALL.encode(MapUtil.getStr(map, "name", ""), CharsetUtil.CHARSET_UTF_8);
        log.info("name: " + name);
        String callBackUrl = String.format(redirectUrl, token, openid, name);
        log.info("callBackUrl: " + callBackUrl);
        return "redirect:" + callBackUrl;
    }
}
